import {logMaker} from '@/utils/log.js';
import * as dat from 'dat.gui';
import {debounceTime, Subject} from 'rxjs';
import {PerspectiveCamera, Scene, sRGBEncoding, WebGLRenderer} from 'three';
import AMapLoader from '@amap/amap-jsapi-loader';
import * as Vue from 'vue/dist/vue.esm-bundler';
import {createPinia} from 'pinia';

class LayerType {
    static TileLayer = "TileLayer"
    static Traffic = "TileLayer.Traffic"
    static RoadNet = "TileLayer.RoadNet"
    static Satellite = "TileLayer.Satellite"
    static Buildings = "Buildings"
    static IndoorMap = "IndoorMap"

    static SkyLayer = "SkyLayer"
    static NebulaLayer = "NebulaLayer"
    static NebulaLabelsLayer = "Nebula.LabelsLayer"
    static InnerLabelsLayer = "Inner.LabelsLayer"
    static VectorLayer = "VectorLayer"
}

const LayerMenu = {
    [LayerType.TileLayer]: "标准图层",
    [LayerType.Traffic]: "实时交通图层",
    [LayerType.RoadNet]: "路网图层 国、省界线",
    [LayerType.Satellite]: "卫星图层",
    [LayerType.Buildings]: "楼块图层",
    [LayerType.IndoorMap]: "室内地图",

    [LayerType.SkyLayer]: "天空图层",
    [LayerType.NebulaLayer]: "基础图层",
    [LayerType.NebulaLabelsLayer]: "文字图层",
    [LayerType.InnerLabelsLayer]: "地区文字图层",
    [LayerType.VectorLayer]: "矢量标记图层",
};

const translation$1 = (CLASS_NAME) => {
    for (let key in LayerMenu) {
        if (CLASS_NAME.includes(key)) {
            return LayerMenu[key];
        }
    }
    return "未知类型：" + CLASS_NAME;
};

class MapStatus {


    static  ShowIndoorMap = "showIndoorMap";
    static  ResizeEnable = "resizeEnable";
    static  DragEnable = "dragEnable";
    static  KeyboardEnable = "keyboardEnable";
    static  DoubleClickZoom = "doubleClickZoom";
    static  ZoomEnable = "zoomEnable";
    static  RotateEnable = "rotateEnable";
    static  ScrollWheel = "scrollWheel";
    static  ZoomSpeed = "zoomSpeed";
    static  AnimateEnable = "animateEnable";
    static  TouchZoom = "touchZoom";
    static  TouchZoomCenter = "touchZoomCenter";
    static  PitchEnable = "pitchEnable";
}

const MapStatusMenu = {
    [MapStatus.ShowIndoorMap]: "室内地图",
    [MapStatus.ResizeEnable]: "监控尺寸变化",
    [MapStatus.DragEnable]: "鼠标拖拽",
    [MapStatus.KeyboardEnable]: "键盘控制",
    [MapStatus.DoubleClickZoom]: "双击放大",
    [MapStatus.ZoomEnable]: "缩放开启",
    [MapStatus.RotateEnable]: "旋转开启",
    [MapStatus.ScrollWheel]: "滚轮开启",
    [MapStatus.ZoomSpeed]: "缩放速度",
    [MapStatus.AnimateEnable]: "动画开启",
    [MapStatus.TouchZoom]: "触控缩放",
    [MapStatus.TouchZoomCenter]: "触控缩放中心",
    [MapStatus.PitchEnable]: "倾角开启",
};

const translation = (key) => {
    let value = MapStatusMenu[key];
    if (value) {
        return value
    } else {
        return ''
    }
};

const out$2 = logMaker('mapLayer', false);
// 获取所有图层
const getAllLayer = (map) => {
    let layers = map.getLayers();
    let list = layers.map(item => {
        return {type: item.CLASS_NAME, info: translation$1(item.CLASS_NAME), layer: item}
    });
    out$2.log(list);
    return layers
};

const out$1 = logMaker('gui', false);


class GMapGui {

    // 地图状态
    mapState = {
        lng: 0,
        lat: 0,
        zoom: 2,
        pitch: 0,
        rotation: 0,
    }
    // 图层
    layers = []
    // 底图
    features = []
    // 控制状态
    status = {}

    /**
     *
     * @param map
     */
    constructor(map) {
        this.map = map;
        this.gui = new dat.GUI();

        this.subject = new Subject();
        this.observable = this.subject.pipe(debounceTime(30));
        this.observable.subscribe(() => this.synchronous());
        this.initStatus();
        this.initMapEvent();

        this.addAll();
    }

    // 初始化状态
    initStatus() {
        let {lng, lat} = this.map.getCenter();
        this.mapState.lng = lng;
        this.mapState.lat = lat;
        this.mapState.zoom = this.map.getZoom();
        this.mapState.pitch = this.map.getPitch();
        this.mapState.rotation = this.map.getRotation();

        this.layers = getAllLayer(this.map).map(layer => ({layer, show: layer.il}));

        this.features = this.map.getFeatures();
        this.status = this.map.getStatus();


    }

    /**
     * 监听地图状态改变
     */
    initMapEvent() {
        // this.map.on('zoomstart', (event) => this.mapStatusChange(event, 'zoomstart'))
        this.map.on('zoomend', (event) => this.mapStatusChange(event, 'zoomend'));

        this.map.on('mapmove', (event) => this.mapStatusChange(event, 'mapmove'));
        // this.map.on('movestart', (event) => this.mapStatusChange(event, 'movestart'))
        this.map.on('moveend', (event) => this.mapStatusChange(event, 'moveend'));

        this.map.on('resize', (event) => this.mapStatusChange(event, 'resize'));

        this.map.on('rightclick', (event) => this.mapStatusChange(event, 'rightclick'));

        const mouseMoveEvent = (event) => this.mapStatusChange(event, 'mousemove');

        this.map.on('mousedown', (event) => {
            this.mapStatusChange(event, 'mousedown');
            this.map.on('mousemove', mouseMoveEvent);
        });
        this.map.on('mouseup', (event) => {
            this.mapStatusChange(event, 'mouseup');
            this.map.off('mousemove', mouseMoveEvent);
        });

    }

    mapStatusChange(event, type) {
        out$1.log(type, event);
        this.initStatus();
        this.subject.next();
    }


    // 同步地图状态
    synchronous() {
        this.mapControl.lng.setValue(this.mapState.lng);
        this.mapControl.lat.setValue(this.mapState.lat);
        this.mapControl.zoom.setValue(this.mapState.zoom);
        this.mapControl.pitch.setValue(this.mapState.pitch);
        this.mapControl.rotation.setValue(this.mapState.rotation);
    }

    // 设置地图状态
    setMapState() {
        let mapState = this.mapState;
        this.map.setZoomAndCenter(mapState.zoom, [mapState.lng, mapState.lat], true);
        this.map.setPitch(mapState.pitch);
        this.map.setRotation(mapState.rotation);
    }


    // 添加所有地图调试工具
    addAll() {
        this.addMapState();
        this.addLayers();
        this.addFeatures();
        this.addMapStatus();
    }

    // 地图状态
    addMapState(show = false) {
        this.mapControl = this.gui.addFolder("地图状态");
        this.mapControl.lng = this.mapControl.add(this.mapState, 'lng', -180, 180, 0.00001).name("经度").onChange(() => this.setMapState());
        this.mapControl.lat = this.mapControl.add(this.mapState, 'lat', -90, 90, 0.00001).name("维度").onChange(() => this.setMapState());
        this.mapControl.zoom = this.mapControl.add(this.mapState, 'zoom', 2, 20, 0.01).name("缩放").onChange(() => this.setMapState());
        this.mapControl.pitch = this.mapControl.add(this.mapState, 'pitch', 0, 83, .1).name("倾角").onChange(() => this.setMapState());
        this.mapControl.rotation = this.mapControl.add(this.mapState, 'rotation', -360, 360, .1).name("旋转").onChange(() => this.setMapState());
        show && this.mapControl.open();

    }


    // 图层控制
    addLayers(show = false) {
        this.layerControl = this.gui.addFolder("图层");

        this.layers.forEach(item => {
            const name = translation$1(item.layer.CLASS_NAME) + item.layer.CLASS_NAME;

            this.layerControl.add(item, 'show')
                .onChange(show => {
                    show ? item.layer.show() : item.layer.hide();
                    this.initStatus();
                })
                .name(name);
        });

        show && this.layerControl.open();
    }


    /**
     * 底图元素
     *
     * bg 区域面
     * point 兴趣点
     * road 道路及道路标注
     * building 建筑物
     */
    addFeatures(show = false) {

        this.featuresControl = this.gui.addFolder("底图内容");
        this.featuresControl.add({show: this.features.includes('bg')}, 'show').name("区域面")
            .onChange((value) => change(value, 'bg'));
        this.featuresControl.add({show: this.features.includes('point')}, 'show').name("兴趣点")
            .onChange((value) => change(value, 'point'));
        this.featuresControl.add({show: this.features.includes('road')}, 'show').name("道路及道路标注")
            .onChange((value) => change(value, 'road'));
        this.featuresControl.add({show: this.features.includes('building')}, 'show').name("建筑物")
            .onChange((value) => change(value, 'building'));

        show && this.featuresControl.open();

        const that = this;

        function change(value, type) {
            if (value) {
                that.features.push(type);
            } else {
                that.features.splice(that.features.indexOf(type), 1);
            }
            that.map.setFeatures(that.features);
        }
    }

    /**
     * 地图控制
     *
     * showIndoorMap: false, // 是否在有矢量底图的时候自动展示室内地图，PC默认true,移动端默认false
     * resizeEnable: true, //是否监控地图容器尺寸变化，默认值为false
     * dragEnable: false, // 地图是否可通过鼠标拖拽平移，默认为true
     * keyboardEnable: false, //地图是否可通过键盘控制，默认为true
     * doubleClickZoom: false, // 地图是否可通过双击鼠标放大地图，默认为true
     * zoomEnable: false, //地图是否可缩放，默认值为true
     * rotateEnable: false, // 地图是否可旋转，3D视图默认为true，2D视图默认false
     */
    addMapStatus(show = false) {
        this.mapStatusControl = this.gui.addFolder("地图交互");
        for (let key in this.status) {
            if (key === 'features') {
                break;
            }
            if (this.status[key] === undefined) {
                out$1.warn(`mapStatus key=>${key} is undefined`);
                break;
            }
            this.mapStatusControl.add(this.status, key)
                .onChange(val => {
                    this.map.setStatus({[key]: val});
                    this.initStatus();
                })
                .name(`${translation(key)} ${key}`);
        }
        show && this.mapStatusControl.open();
    }

    remove() {
        this.gui.domElement.remove();
        this.gui = undefined;
    }
}

class GMap {

    static MapLoading = false;

    /**
     * constructor
     * @param elmId{String}
     * @param conf{Object}
     */
    constructor(elmId, conf = {}) {
        this.out = logMaker("GMap");
        this.map = new AMap.Map(elmId, conf);
    }

    // 完成
    complete() {
        return new Promise((resolve) => {
            this.map.on('complete', () => {
                this.out.log("map complete");
                GMap.MapLoading = false;
                resolve();
            });
        })
    }

    openGui() {
        return new GMapGui(this.map)
    }

}

let out = logMaker("three layer");
let camera, scene, renderer, customCoords;


const initThreeLayer = (map) => {
    customCoords = map.customCoords;
    let {lng, lat} = map.getCenter();
    customCoords.setCenter([lng, lat]);


    const initThree = (gl) => {
        camera = new PerspectiveCamera(60, window.innerWidth / window.innerHeight, 100, 1 << 30);
        renderer = new WebGLRenderer({
            context: gl,
            alpha: true,
            antialias: true,// 抗锯齿
        });
        renderer.autoClear = false;
        renderer.outputEncoding = sRGBEncoding;

        scene = new Scene();

    };

    const animate = () => {
        map.render();
        requestAnimationFrame(animate);
    };

    const resize = () => {
        window.addEventListener('resize', () => {
            camera.aspect = window.innerWidth / window.innerHeight;
            camera.updateProjectionMatrix();
            renderer.setSize(window.innerWidth, window.innerHeight);
        });
    };


    return new Promise((resolve, reject) => {

        const threeLayer = new AMap.GLCustomLayer({
            zIndex: 10,
            // visible: true,
            init: (gl) => {
                initThree(gl);
                resize();
                animate();
                out.log("init complete");
                resolve();
            },
            render: () => {
                // 这里必须执行！重新设置 three 的 gl 上下文状态
                renderer.resetState();

                const {near, far, fov, up, lookAt, position} = customCoords.getCameraParams();

                camera.near = near;
                camera.far = far;
                camera.fov = fov;
                camera.position.set(...position);
                camera.up.set(...up);
                camera.lookAt(...lookAt);
                camera.updateProjectionMatrix();

                renderer.render(scene, camera);

                // 这里必须执行！重新设置 three 的 gl 上下文状态
                renderer.resetState();
            }
        });
        map.add(threeLayer);
    })
};

class BaseGInfoWindow {

    constructor(component) {
        this.component = component;
        this.element = document.createElement('div');

        this.infoWindow = new AMap.InfoWindow({
            content: this.element
        });
    }

    createApp() {

    }


}

class GInfoWindow3 extends BaseGInfoWindow {

    constructor(component) {
        super(component);
    }

    createApp(conf) {
        super.createApp();
        let app = Vue.createApp({
            components: {comp: this.component},
            template: `
              <comp/>`,
            ...conf
        });
        app.use(createPinia());
        app.mount(this.element);
        this.app = app;
    }
}

/**
 * 初始化地图
 * @param key{String}               Key
 * @param code{String}              安全密钥
 * @param plugins{Array<String>}    插件
 * @return {Promise<void>}
 * @constructor
 */
const InitAMap = async ({key, code, plugins}) => {
    window._AMapSecurityConfig = {
        securityJsCode: code,
    };

    window.AMap = await AMapLoader.load({
        key: key,
        version: '2.0',
        plugins: plugins,
    });
};

export {GInfoWindow3 as GInfoWindow, GMap, GMapGui, InitAMap, initThreeLayer};
